package handler

import (
	"context"
	"errors"
	"fmt"
	"hertz/demo/biz/model"
	"hertz/demo/biz/mw"
	"hertz/demo/biz/util"
	"net/http"

	"github.com/cloudwego/hertz/pkg/app"
	"github.com/cloudwego/hertz/pkg/common/hlog"
	"github.com/cloudwego/hertz/pkg/common/utils"
	"gorm.io/gorm"
)

func ListSelection(ctx context.Context, c *app.RequestContext) {

	status := c.Query("status")
	author, err := util.GetQueryUintOption(c, "author")
	if err != nil {
		util.BadRequest(c, err)
		return
	}

	ret := []model.Selection{}
	builder := mw.GetDB(c)
	if status != "" {
		builder = builder.Where("status = ?", status)
	}
	if author != nil {
		builder = builder.Where("author_id = ?", *author)
	}
	err = builder.Find(&ret).Error
	if err != nil {
		hlog.CtxErrorf(ctx, "GetSampleSelection db error: %w", err)
		return
	}

	c.JSON(http.StatusOK, ret)
}

func FindSelectionById(ctx context.Context, c *app.RequestContext) {
	id, err := util.GetParamUint(c, "id")
	if err != nil {
		util.BadRequest(c, err)
		return
	}

	ret, err := model.FindSelectionById(mw.GetDB(c), uint(id))
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.NotFound()
		} else {
			hlog.CtxErrorf(ctx, "FindSelectionById, db error: %w", err)
			util.ErrMessage(c, http.StatusBadRequest, "db error")
		}
		return
	}
	c.JSON(http.StatusOK, ret)
}

func UpdateSelectionStatus(ctx context.Context, c *app.RequestContext) {
	type Req struct {
		Status string `json:"status"`
	}

	id, err := util.GetParamUint(c, "id")
	if err != nil {
		util.BadRequest(c, err)
		return
	}

	var req Req
	if err := c.BindAndValidate(&req); err != nil {
		util.BadRequest(c, err)
		return
	}
	if !model.IsValidSelectionStatus(req.Status) {
		util.BadRequest(c, fmt.Errorf("invalid status: %s", req.Status))
		return
	}

	user := mw.GetUser(c)
	if user == nil {
		util.ErrMessage(c, http.StatusUnauthorized, "Unauthorized")
		return
	}

	if req.Status == model.LABEL_CONFIRM && !user.Admin {
		util.ErrMessage(c, http.StatusUnauthorized, "Unauthorized")
		return
	}

	if err := model.UpdateSelectionStatus(mw.GetDB(c), uint(id), req.Status, user.Admin, uint(user.Id)); err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			util.NotFound(c)
			return
		}
		hlog.CtxErrorf(ctx, "UpdateSelectionStatus, error: %w", err)
		util.ErrMessage(c, http.StatusInternalServerError, "db error")
		return
	}

	c.Status(http.StatusOK)
}

func AddSelection(ctx context.Context, c *app.RequestContext) {
	var value model.Selection
	if err := c.BindAndValidate(&value); err != nil {
		util.BadRequest(c, err)
		return
	}

	if err := model.AddSelection(mw.GetDB(c), &value); err != nil {
		hlog.CtxErrorf(ctx, "AddSelection db error: %w", err)
		util.ErrMessage(c, http.StatusInternalServerError, "db error")
		return
	}
	c.JSON(http.StatusOK, utils.H{"id": value.ID})
}

func UpdateSelection(ctx context.Context, c *app.RequestContext) {
	var value model.Selection
	if err := c.BindAndValidate(&value); err != nil {
		util.BadRequest(c, err)
		return
	}

	user := mw.GetUser(c)
	if user == nil {
		util.ErrMessage(c, http.StatusUnauthorized, "unauthorized")
		return
	}

	err := model.UpdateSelection(mw.GetDB(c), &value, user.Admin, uint(user.Id))
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.NotFound()
			return
		}
		if errors.Is(err, util.ErrCanRet{}) {
			util.ErrMessage(c, http.StatusInternalServerError, err.Error())
			return
		}
		hlog.CtxErrorf(ctx, "UpdateSelection db error: %w", err)
		util.ErrMessage(c, http.StatusBadRequest, "db error")
		return
	} else {
		c.JSON(http.StatusOK, value)
		return
	}
}

func UpdateSelectionComment(ctx context.Context, c *app.RequestContext) {
	type Req struct {
		Comment string `json:"comment"`
	}

	id, err := util.GetParamUint(c, "id")
	if err != nil {
		util.BadRequest(c, err)
		return
	}

	var req Req
	if err := c.BindAndValidate(&req); err != nil {
		util.BadRequest(c, err)
		return
	}

	user := mw.GetUser(c)
	if user == nil {
		util.ErrMessage(c, http.StatusUnauthorized, "unauthorized")
		return
	}

	db := mw.GetDB(c)
	err = model.UpdateSelectionComment(db, uint(id), req.Comment, user.Admin, uint(user.Id))
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			util.NotFound(c)
		} else {
			hlog.CtxErrorf(ctx, "UpdateSelectionComment db error: %w", err)
			util.ErrMessage(c, http.StatusBadRequest, "db error")
		}
		return
	}
	c.Status(http.StatusOK)
}

func DeleteSelection(ctx context.Context, c *app.RequestContext) {
	id, err := util.GetParamUint(c, "id")
	if err != nil {
		util.BadRequest(c, err)
	}

	user := mw.GetUser(c)
	if user == nil {
		util.ErrMessage(c, http.StatusUnauthorized, "unauthorized")
		return
	}

	if err := model.DeleteSelection(mw.GetDB(c), uint(id), user.Admin, uint(user.Id)); err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.NotFound()
			return
		}

		hlog.CtxErrorf(ctx, "DeleteSelection db error: %w", err)
		util.ErrMessage(c, http.StatusInternalServerError, "db error")
		return
	}

	c.Status(http.StatusOK)
}
